﻿using Modbus.Messages;

namespace Modbus
{
	partial class ModbusClient
	{
		public short[] ReadWriteMultipleRegisters(byte slaveAddress, int readStartingAddress, int readQuantity,
			int writeStartingAddress, short[] writeRegisters)
		{
			//
			// Input arguments validation.
			//

			Ensure.ArgumentNotEqualTo(SR.Argument_slaveAddress, slaveAddress, BroadcastAddress);
			Ensure.ArgumentInRange(SR.Argument_readStartingAddress, readStartingAddress, MinDataAddress, MaxDataAddress);
			Ensure.ArgumentInRange(SR.Argument_readQuantity, readQuantity, ModbusSpecification.MinQuantity,
				ModbusSpecification.ReadWriteMultipleRegistersMaxReadQuantity);
			Ensure.ArgumentInRange(SR.Argument_writeStartingAddress, writeStartingAddress, MinDataAddress, MaxDataAddress);
			Ensure.ArrayOfRequiredLength(SR.Argument_writeRegisters, writeRegisters, ModbusSpecification.MinQuantity,
				ModbusSpecification.ReadWriteMultipleRegistersMaxWriteQuantity);

			//
			// Internal state validation.
			//

			this.ThrowIfDisposed();

			//
			// Request creation.
			//

			ReadWriteMultipleRegistersRequest request = new ReadWriteMultipleRegistersRequest();

			request.FunctionCode = FunctionCodes.ReadWriteMultipleRegisters;
			request.ReadStartingAddress = (ushort)(readStartingAddress);
			request.ReadQuantity = (ushort)(readQuantity);
			request.WriteStartingAddress = (ushort)(writeStartingAddress);
			request.WriteQuantity = (ushort)(writeRegisters.Length);
			request.WriteRegisters = DataUtility.EncodeRegisters(writeRegisters);

			//
			// Perform transaction.
			//

			var response = this.transport.Request<ReadDataResponse>(slaveAddress, request);

			//
			// Response validation.
			//

			int excpectedByteCount = (2 * request.ReadQuantity);

			if (response.Data.Length != excpectedByteCount)
			{
				throw new MismatchResponseException(SR.ModbusMessageField_ByteCount);
			}

			//
			// Prepare return value.
			//

			short[] registers = DataUtility.DecodeRegisters(response.Data);

			return registers;
		}
	}
}
